package com.benyi.util.rest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jakarta.servlet.http.HttpServletResponse;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream; 
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Base64;
import java.util.Iterator;
import java.util.Vector;

public class ImageUtil {
    private static Logger log =LoggerFactory.getLogger(ImageUtil.class);

    public static String saveImageBase64(String img,String dir,long imageId,String subId){
        String flag=";base64,";
        int index=img.indexOf(flag); //data:image/jpeg;base64,
        if(index<1){
            return null;
        }
        String type=getImageTypeFromBase64(img.substring(0,index));
        if(type==null){
            return null;
        }
        Base64.Decoder d=Base64.getDecoder();

        String content=img.substring(index+flag.length());

        log.debug("imageType={},content={}",type,content);

        byte []bytes= d.decode(content);

        String file=ImageUtil.saveImage(imageId,type,bytes,dir,subId);
        return file;
    }

    public static String saveImage(long imageId,String type,byte []img,String dir,String subId){
        String subDir=String.valueOf(imageId%100);
        while(subDir.length()<2){
            subDir="a"+subDir;
        }

        File to=new File(dir,subDir);
        if(to.exists()==false){
            to.mkdirs();
        }
        long ran= (long)(Math.random()*System.currentTimeMillis());
        if(ran<0){
            ran=ran*(-1);
        }
        ran=ran%100;

        String name;
        if(subId != null){
            name=String.valueOf(imageId)+"_"+subId+"_"+String.valueOf(ran) + "." + type;
        }else{
            name=String.valueOf(imageId)+"_"+String.valueOf(ran) + "." + type;
        }

        File file=new File(to,name);

        log.debug("保存图像文件到文件:{}",file.getAbsolutePath());
        boolean save=false;
        try {
            FileOutputStream os=new FileOutputStream(file);
            try {
                os.write(img);
                os.close();
                save=true;
            } catch (IOException e) {
                log.error("保存文件失败",e);
            }
        } catch (FileNotFoundException e) {
            log.error("保存文件失败",e);
        }
        if(save){
            String n=subDir+"/"+name;
            return n;
        }
        return null;
    }

    public static String getImageTypeFromBase64(String img){
        String flag="data:";
        int index=img.indexOf(flag);
        if(index<0){
            return null;
        }
        String type=img.substring(index+flag.length());
        flag="image/";
        if(type.startsWith(flag)==false){
            return null;
        }
        type=type.substring(flag.length());
        if(type.length()==0){
            return null;
        }
        return type;
    }

    private static byte[] readImage(File f){
        ByteArrayOutputStream bo=null;
        BufferedInputStream bi=null;
        try {
            bo=new ByteArrayOutputStream();
            bi=new BufferedInputStream(new FileInputStream(f));
            int i=bi.read();
            while(i!=-1){
                bo.write(i);
                i=bi.read();
            }
            return bo.toByteArray();
        } catch (Exception e) {
            log.error("读文件过程异常",e);
        }finally {
            try{
                if(bi!=null){
                    bi.close();
                }
                if(bo!=null){
                    bo.close();
                }
            }catch(Exception x){}
        }
        return null;
    }

    public static boolean writeImage(File f,HttpServletResponse res){
        if(f==null){
            return false;
        }
        String name=f.getName();
        byte []img=readImage(f);
        if(img==null){
            return false;
        }
        int index=name.lastIndexOf(".");
        String type="image/"+name.substring(index+1);
        res.setHeader("Content-Type", type);
        try{
            OutputStream out=res.getOutputStream();
            out.write(img);
            out.flush();
            return true;
        }catch(Exception e){
            log.error("输出图像内容异常",e);
        }
        return false;
    } 
    
    public static String saveImageBase64(String img,String dir,String sub,String file){
        String flag=";base64,";
        int index=img.indexOf(flag); //data:image/jpeg;base64,
        if(index<1){
            return null;
        }
        String type=getImageTypeFromBase64(img.substring(0,index));
        if(type==null){
            return null;
        }
        Base64.Decoder d=Base64.getDecoder();

        String content=img.substring(index+flag.length());

       // log.debug("imageType={},content={}",type,content); 
        
        byte []bytes= d.decode(content);

        File to=new File(dir,sub);
        if(to.exists()==false){
            to.mkdirs();
        } 
        file=file.toLowerCase();
        type=type.toLowerCase();
        
        if(file.endsWith("."+type)==false) {
        	file=file+"."+type; //确保文件扩展名正确 
        }
        
        File f=new File(to,file); 
        log.debug("保存图像文件到文件:{}",f.getAbsolutePath());
        boolean save=false;
        try {
            FileOutputStream os=new FileOutputStream(f);
            try {
                os.write(bytes);
                os.close();
                save=true;
            } catch (IOException e) {
                log.error("保存文件失败",e);
            }
        } catch (FileNotFoundException e) {
            log.error("保存文件失败",e);
        }
        if(save){
            String n=sub+"/"+file;
            return n;
        }
        return null;
    }
    
    
    public static String saveFileBase64(String content,String dir,String sub,String file,String ext){
         
        Base64.Decoder d=Base64.getDecoder();
 
        byte []bytes= d.decode(content);

        File to=new File(dir,sub);
        if(to.exists()==false){
            to.mkdirs();
        } 
        if(ext==null || ext.length()==0) {
        	ext="null";
        }
        file=file.toLowerCase();
        ext=ext.toLowerCase();
        
        if(file.endsWith("."+ext)==false) {
        	file=file+"."+ext; //确保文件扩展名正确 
        }
        
        File f=new File(to,file); 
        log.debug("保存一般文件到文件:{}",f.getAbsolutePath());
        boolean save=false;
        try {
            FileOutputStream os=new FileOutputStream(f);
            try {
                os.write(bytes);
                os.close();
                save=true;
            } catch (IOException e) {
                log.error("保存文件失败",e);
            }
        } catch (FileNotFoundException e) {
            log.error("保存文件失败",e);
        }
        if(save){
            String n=sub+"/"+file;
            return n;
        }
        return null;
    }
    
    public static void scale(File file,int width,int height) throws IOException {
    	  
    	FileInputStream fi=new FileInputStream(file);
    	ImageInputStream is=ImageIO.createImageInputStream(fi);
    	Iterator<ImageReader> it=ImageIO.getImageReaders(is);
    	String n=file.getName();
		File to=new File(file.getAbsolutePath()+"."+System.currentTimeMillis());
		ByteArrayOutputStream mo=new ByteArrayOutputStream();
		
		if(it.hasNext()) {
			ImageReader rd = it.next();
			rd.setInput(is, true); 
			int iw=rd.getWidth(0);
			int ih=rd.getHeight(0);
			
			if(iw<width && ih<height) {
				fi.close();
				is.close();
				return;
			}
			int rw=10;
			int rh=10;
			int r=10;
			
			int x=0;
	    	int y=0;
	    	
			if(width>0 && height>0) { //如果指定了 目标  宽， 高， 则按这个目标进行切割
				rw=(iw*10)/width;
		    	rh=(ih*10)/height;
		    	r=(rw>rh)?rh:rw;
		    	x=(10*iw-r*width)/20; //对指定了 宽， 高的 ， 切割点 X 
		    	y=(10*ih-r*height)/20; //对指定了 宽， 高的 ， 切割点 Y 
			}else {
				x=0;
				y=0;
				if(width>0) {   
					r=(iw*10)/width;  //如 只有 宽， 按宽度 进行切割 
					height=(ih*10)/r; //按宽比 计算高度
				}else {
					r=(ih*10)/height;  //如 只有高， 按高度 进行切割 
					width=(iw*10)/r;
				} 
			}
	    	
			ImageReadParam param = rd.getDefaultReadParam(); 
			int sw=(r*width)/10;
			int sh=(r*height)/10;
			Rectangle rect=null;
			
			double scale_x=10.0/r;
	        double scale_y=10.0/r; 
			 
		    rect = new Rectangle(x, y, sw, sh); //创建要截取的矩形范围 
			 
	        param.setSourceRegion(rect); //设置截取范围参数 
	        BufferedImage bi = rd.read(0, param); //读取截图数据  
	        
	        AffineTransformOp ato = new AffineTransformOp(AffineTransform.getScaleInstance(scale_x, scale_y), null);
	        BufferedImage bit = ato.filter(bi, null);   
			 
	        ImageIO.write(bit,n.substring(n.lastIndexOf(".")+1), mo);
	        mo.flush(); 
		}
		
		is.close();
		fi.close();
		fi=null;
		is=null; 
		
		byte []mb=mo.toByteArray();
		if(mb.length>0) {
			FileOutputStream out=new FileOutputStream(file);
			out.write(mb);
			out.close();
			out=null;
			log.debug("save cutted image to file={}", file.getAbsolutePath() );
		} 
    }
    
    
    public static void scale(File file,double scale_x,double scale_y) throws IOException {
  	  
    	FileInputStream fi=new FileInputStream(file);
    	ImageInputStream is=ImageIO.createImageInputStream(fi);
    	Iterator<ImageReader> it=ImageIO.getImageReaders(is);
    	String n=file.getName();
		File to=new File(file.getAbsolutePath()+"."+System.currentTimeMillis());
		ByteArrayOutputStream mo=new ByteArrayOutputStream();
		
		if(it.hasNext()) {
			ImageReader rd = it.next();
			rd.setInput(is, true);  
			int iw=rd.getWidth(0);
			int ih=rd.getHeight(0);
			ImageReadParam param = rd.getDefaultReadParam(); 
			Rectangle rect = new Rectangle(0, 0, iw, ih); 
			param.setSourceRegion(rect); //设置截取范围参数 
	        BufferedImage bi = rd.read(0, param); //读取截图数据  
	        
	        AffineTransformOp ato = new AffineTransformOp(AffineTransform.getScaleInstance(scale_x, scale_y), null);
	        BufferedImage bit = ato.filter(bi, null);   
			
	        ImageIO.write(bit,n.substring(n.lastIndexOf(".")+1), mo);
	        mo.flush(); 
		}
		is.close();
		fi.close();
		fi=null;
		is=null;
		
		byte []mb=mo.toByteArray();
		if(mb.length>0) {
			FileOutputStream out=new FileOutputStream(file);
			out.write(mb);
			out.close();
			out=null;
			log.debug("save cutted image to file={}", file.getAbsolutePath() );
		} 
    }
    
    public static void scale(String dir,String file,int width,int height) {
    	Scaler.putTask(dir,file,width,height);
    	if(thread==null) {
    		thread=new Scaler();
    		thread.start();
    	} 
    }
    
    public static void scale(String dir,String file,double sx,double sy) {
    	Scaler.putTask(dir,file,sx,sy);
    	if(thread==null) {
    		thread=new Scaler();
    		thread.start();
    	} 
    }
    
    static Scaler thread;
    
    static class Scaler extends Thread {
    	static private Vector<ScalerTask> v=new Vector<ScalerTask>();
    	
    	public void run() { 
    		while(v.size()>0) { 
    			try { 
    				ScalerTask t=v.remove(0); 
    				File f=new File(t.dir,t.file);
    				if(t.width==0 && t.height==0) {
    					scale(f,t.scale_x,t.scale_y); 
    				}else {
    					scale(f,t.width,t.height); 
    				} 
    				Thread.sleep(128);
    			}catch(Exception e) {
    				log.error("裁剪图片作业异常", e);
    			}
    		}
    		thread=null; 
    	}
    	
    	public static void putTask(String dir,String file,int width,int height) {
    		ScalerTask t=new ScalerTask();
    		t.dir=dir;
    		t.file=file;
    		t.width=width;
    		t.height=height; 
    		v.addElement(t);
    	}
    	
    	public static void putTask(String dir,String file,double sx,double sy) {
    		ScalerTask t=new ScalerTask();
    		t.dir=dir;
    		t.file=file;
    		t.scale_x=sx;
    		t.scale_y=sy; 
    		v.addElement(t);
    	}
    }
    
    static class ScalerTask{
    	String dir;
    	String file;
    	int width=0;
    	int height=0;
    	double scale_x;
    	double scale_y; 
    }
    
    public static void main(String []args) throws Exception  {
    	File f=new File("e:/tmp/2");
    	File []fs=f.listFiles();
    	for(int i=0;i<fs.length;i++) {
    		//scale("e:/tmp/2",fs[i].getName(),0.2,0.2);
    		//scale("e:/tmp/2",fs[i].getName(),240,200);
    		scale("e:/tmp/2",fs[i].getName(),3000,0);
    	}
    	System.out.println("finished");
    }
}
